﻿using System;
using System.Collections.Generic;
using System.Text;
using LitJson;
using System.Web.Security;

namespace Light.Utility.OAuth
{
    /// <summary>
    ///  微信授权工具类
    /// </summary>
    public class WeixinHelper
    {

        /// <summary>
        /// 网页授权获取code，请在config.ReturnUrl页面接收code值
        /// </summary>
        /// <param name="config">config需要值AppType，AppId，ReturnUrl，Scope，State</param>
        public static void Redirect4Code(OAuthConfig config)
        {
            string url = string.Empty;

            if (config.AppType == AppType.Website)
            {
                url = string.Format("https://open.weixin.qq.com/connect/qrconnect?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state={3}#wechat_redirect", config.AppId, config.ReturnUrl, config.Scope, config.State);
            }
            else
            {
                url = string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state={3}#wechat_redirect", config.AppId, config.ReturnUrl, config.Scope, config.State);
            }

            WebHelper.CurContext.Response.Redirect(url);
        }

        /// <summary>
        /// 根据appId、appSecret、code获取网页授权access_token,有效期2小时
        /// </summary>
        /// <param name="config"></param>
        /// <param name="code"></param>
        /// <returns>Dictionary</returns>
        public static Dictionary<string, object> GetAccessToken(OAuthConfig config, string code)
        {
            if (String.IsNullOrEmpty(code))
                throw new Exception("WexinHelper.GetAccessToken(config,code) 参数 code 为空");

            string sessionKey = "oauth_access_token_" + config.AppId + config.AppKey;

            if (WebHelper.GetSession(sessionKey) == null)
            {
                //获得配置信息
                string send_url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", config.AppId, config.AppKey, code);
                string result = WebHelper.HttpGet(send_url, Encoding.UTF8);

                if (result.Contains("errcode"))
                {
                    throw new Exception(result);
                }
                try
                {
                    Dictionary<string, object> dic = JsonMapper.ToObject<Dictionary<string, object>>(result);

                    WebHelper.SetSession(sessionKey, dic, 60);

                    return dic;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message + " \r\n" + result);
                }
            }
            else
            {
                return WebHelper.GetSession<Dictionary<string, object>>(sessionKey);
            }
        }

        /// <summary>
        /// 拉取用户信息(需scope为 snsapi_userinfo)
        /// </summary>
        /// <param name="accessToken">通过GetAccessToken(config,code)获取到的</param>
        /// <param name="openid"></param>
        /// <returns>JsonData</returns>
        public static JsonData GetUserInfo(string accessToken, string openid)
        {
            if (String.IsNullOrEmpty(accessToken))
                throw new Exception("WexinHelper.GetUserInfo(accessToken,openid) 参数 accessToken 为空");
            if (String.IsNullOrEmpty(openid))
                throw new Exception("WexinHelper.GetUserInfo(accessToken,openid) 参数 openid 为空");

            string sessionKey = "oauth_userinfo_" + accessToken;

            if (WebHelper.GetSession(sessionKey) == null)
            {

                string url_userinfo = string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN", accessToken, openid);
                string result = WebHelper.HttpGet(url_userinfo, Encoding.UTF8);

                if (result.Contains("errcode"))
                {
                    throw new Exception(result);
                }
                try
                {

                    string jsonStr = result;
                    if (StringHelper.ContainsEmoji(result))
                    {
                        jsonStr = StringHelper.FilterEmoji(result);
                    }
                    JsonData dic = JsonMapper.ToObject(jsonStr);

                    WebHelper.SetSession(sessionKey, dic, 60);

                    return dic;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message + " \r\n" + result);
                }
            }
            else
            {
                return WebHelper.GetSession<JsonData>(sessionKey);
            }
        }

        /// <summary>
        /// 获取基础操作的token 有效期2小时
        /// </summary>
        /// <param name="config"></param>
        /// <param name="latest">获取最新token</param>
        /// <returns></returns>
        public static string GetBasicToken(OAuthConfig config, bool latest)
        {
            if (String.IsNullOrEmpty(config.AppId))
                throw new Exception("WexinHelper.GetBasicToken(config) 参数 AppId 为空");
            if (String.IsNullOrEmpty(config.AppKey))
                throw new Exception("WexinHelper.GetBasicToken(config) 参数 AppKey 为空");

            string sessionKey = "basic_token_" + config.AppId + config.AppKey;
            string token = WebHelper.GetSession(sessionKey);

            if (String.IsNullOrEmpty(token) || latest)
            {
                string data = null;
                try
                {
                    string requestUrl = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", config.AppId, config.AppKey);
                    data = WebHelper.HttpGet(requestUrl, Encoding.UTF8);

                    LitJson.JsonData jo = LitJson.JsonMapper.ToObject(data);
                    token = jo["access_token"].ToString();

                    WebHelper.SetSession(sessionKey, token, 60);
                }
                catch (Exception ex)
                {
                    throw new Exception(data);
                }
            }
            return token;
        }

        /// <summary>
        /// 清除BasicToken缓存
        /// </summary>
        /// <param name="config"></param>
        public static void RefreshBasicToken(OAuthConfig config)
        {
            string sessionKey = "basic_token_" + config.AppId + config.AppKey;
            WebHelper.SetSession(sessionKey, null);
        }

        /// <summary>
        /// 获取用户基本信息（包括UnionID机制）
        /// 需要前往微信开放平台（open.weixin.qq.com）绑定公众号后，才可利用UnionID机制
        /// </summary>
        /// <param name="config">用appId,appSecret获取基础操作的token</param>
        /// <param name="openid">用户的openid</param>
        /// <returns></returns>
        public static JsonData GetUser(OAuthConfig config, string openid)
        {
            string basicToken = GetBasicToken(config, false);
            return GetUser(basicToken, openid);
        }

        /// <summary>
        /// 获取用户基本信息（包括UnionID机制）
        /// 需要前往微信开放平台（open.weixin.qq.com）绑定公众号后，才可利用UnionID机制
        /// </summary>
        /// <param name="basicToken">基础操作的token</param>
        /// <param name="openid">用户的openid</param>
        /// <returns></returns>
        public static JsonData GetUser(string basicToken, string openid)
        {
            if (String.IsNullOrEmpty(openid))
                throw new Exception("WexinHelper.GetUser(basicToken,openid) 参数opendid为空");

            string sessionKey = "user_info_" + basicToken;
            JsonData jsonData = WebHelper.GetSession<JsonData>(sessionKey);

            if (jsonData == null)
            {
                string url_userinfo = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", basicToken, openid);
                string result = WebHelper.HttpGet(url_userinfo, Encoding.UTF8);

                //TextHelper.AppendString(
                //   string.Format("E:\\ftp\\log_wx_userinfo_{0}.txt", DateTime.Now.ToString("yyyyMMdd")),
                //   string.Format("{0}=============\r\n{1}", DateTime.Now, result));

                if (result.Contains("errcode"))
                {
                    throw new Exception(result);
                }
                try
                {
                    string jsonStr = result;
                    if (StringHelper.ContainsEmoji(result))
                    {
                        jsonStr = StringHelper.FilterEmoji(result);
                    }
                    jsonData = JsonMapper.ToObject(jsonStr);
                    WebHelper.SetSession(sessionKey, jsonData, 60);
                }
                catch (Exception ex)
                {
                    //TextHelper.AppendString(
                    //   string.Format("E:\\ftp\\log_wx_userinfo_{0}.txt", DateTime.Now.ToString("yyyyMMdd")),
                    //   string.Format("{0}=============\r\nJsonMapper.ToObject出错了\r\njsonStr：{1}", DateTime.Now, result));

                    throw new Exception(ex.Message + " \r\n" + result);
                }
            }
            return jsonData;
        }

        /// <summary>
        /// 验证服务器配置的Token(令牌)
        /// </summary>
        /// <param name="token"></param>
        public static void ValidateServerToken(string token)
        {
            string signature = WebHelper.CurContext.Request.QueryString["signature"];
            string timestamp = WebHelper.CurContext.Request.QueryString["timestamp"];
            string nonce = WebHelper.CurContext.Request.QueryString["nonce"];
            string[] ArrTmp = { token, timestamp, nonce };

            Array.Sort(ArrTmp); //字典排序
            string tmpStr = string.Join("", ArrTmp);

            tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
            tmpStr = tmpStr.ToLower();

            bool isSuccess = tmpStr.Equals(signature);

            if (isSuccess)
            {
                string echoStr = WebHelper.CurContext.Request.QueryString["echoStr"];
                if (!string.IsNullOrEmpty(echoStr))
                {
                    WebHelper.CurContext.Response.Write(echoStr);
                    WebHelper.CurContext.Response.End();
                }
            }
        }
    }
}
